#include "vtkFieldImport_boundary.hpp"


namespace hms::vtk
{


template<typename T>
maybe_const_XMLElement<T>* findFieldData(
	T* cellData,
	const std::string& fieldName,
	Index nComponents
){
	maybe_const_XMLElement<T>* dataArray {
		getChildNodeByAttributeValue( cellData, "DataArray", "Name", fieldName )
	};
	/* if a value was provided, check whether it matches */
	if ( nComponents == signalCode::uninitialised ||
		dataArray->Attribute(
			nComponentsName, std::to_string(nComponents).c_str() )
	){
		return dataArray;
	}
	throw ParseError( "Field \""s + fieldName
		+ "\", attribute \"NumberOfComponents\": Unexpected value. Expected value: "
		+ std::to_string(nComponents)
	);
}



template<typename SolverType>
void readDomainFields(
	const xml::XMLElement* vtk,
	SolverBase<SolverType>& solver,
	bool skipZField
){
	using S = SolverBase<SolverType>;
	using MeshType = typename S::MeshType;
	using FieldName = typename S::FieldName;
	constexpr static FieldName zFieldName { S::zFieldName() };

	const xml::XMLElement* cellData { getCellData<MeshType>(vtk) };

	/* we need to set the z field first, so that the values can be used in
	 * functions for setting other fields. It's the same process, so we
	 * put it in a lambda */
	auto readDomainOf = [&](FieldName fieldName){
		std::string fieldNameStr { magic_enum::enum_name(fieldName) };

		Field<MeshType>& field { solver.field(fieldName) };

		std::vector<FunctionParserWrapper> fParsers {
			readDomainValues( cellData, field, fieldNameStr )
		};

		if ( !fParsers.empty() ){
			setFieldByFunctions<NonUniform>(
				field.values(),
				fParsers,
				solver,
				fieldName != zFieldName
			);
		}
		/* to avoid uninitialised values, we set all corners to zero */
		setCorners(field.values(), field.mesh(),
			FieldBase<Field<MeshType>>::cornerValue
		);
	};

	/* z field first */
	if ( !skipZField )
		readDomainOf(zFieldName);

	/* now the other fields */
	for ( int i{0}; i < S::nFields ; ++i ){
		FieldName fieldName { static_cast<FieldName>(i) };
		if ( fieldName != zFieldName )
			readDomainOf(fieldName);
	}
}


template<typename SolverType>
void readDomainFields(
	const xml::XMLDocument* doc,
	SolverBase<SolverType>& solver,
	bool skipZField
){
	const xml::XMLElement* vtk { getVtkNode(doc) };

	readDomainFields(vtk, solver, skipZField);
	// readBoundaryConditions(vtk, solver, skipZField);
}


} // namespace hms::vtk
